
                /*********************************************
                **                                          **
                **                                          **
                **              gp.i.asgn.l.b1.C            **
                **                                          **
                **                                          **
                *********************************************/
                /*********************************************
                **                                          **
                **         Author Jean-Marc Adamo           **
                **       Copyright (C) 1997-2008 JMA        **
                *********************************************/


/* 
1.14.1. Assignment and indirect Access Global:
        *global_d_ptr = *global_s_ptr.

Such an assignment involves reading a remote data via
the global pointer global_s_ptr and writing this data
to a remote location via the global pointer global_d_ptr.

The rhs pointer must always be set with Sdf::NOCP in order
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
to allow blocking reading only.This allow the library to
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
automatically synchronize the end of reading with the start 
of subsequent writing

The way the lhs pointer set informs the library whether or 
not writing is blocking.

When the lhs pointer is set with Sdf::NOCP, writing blocking. 
Control returns from the assignment statement only when writing 
has been completed.

When the lhs pointer is set with th pointer ot a RWCtrl record 
control returns immediately from the assignment. The completion 
event is asynchronously handled by a handler that the programmer 
has passed to the global pointer via the RWCtrl record at pointer 
construction.

A notable particular case occurs when the lhs global pointer 
refers to a local object. (into the process) 
            ^^^^^^^^^^^^
In this case control returns from the assignment statement after 
writing has been completed and the completion handler (if one 
has been provided) has been executed. Therefore, in this case,
writing works as a blocking writing whether or not a RWCtrl 
record has been passed to the global pointer at definition.


In the sample code below, both reading and writing are blocking:
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*global_d_ptr = *global_s_ptr is an assignement using global 
pointers that copies an integer from the previous-rank process 
to the local process (circularly).

Access to data in reading is indirect: the data address is computed 
on the fly by rwloc_fct. It is direct in writing. The local pointer 
to destination  is turned into a global by using a special constructor 
intended to this purpose.Writing have been made blocking (implicite 
Sdf::NOCP set at construction).
*/

#include "arch.h"

Global_id gid1;
Global_id gid2;
Coll_id cid1, cid2;

void init_gid(int, char **){
   gid1.set();
   gid2.set();
   cid1.set();
   cid2.set();
   fprintf(Sdf::trace, "node%d: gid1.tag=%d, gid2.tag=%d, cid1.tag=%d, cid2.tag=%d\n",
                Sdf::PROC_ID, gid1.get(), gid2.get(), cid1.get(), cid2.get());
   fflush(Sdf::trace);
}


int *source_data_ptr;

void rts_handler(void *){
   fprintf(Sdf::trace, "node%d: global-reading's over on target side\n", Sdf::PROC_ID);
   fflush(Sdf::trace);
}

int *rloc_fct(IDH_rcd *ptr){
   fprintf(Sdf::trace, "node%d: loc_fct, src_proc=%d, sz=%d, sent-sz=%d, tag_ev=%d, tag_av=%d, offset=%d, rarg0=%d, rarg1=%d\n",
           Sdf::PROC_ID, ptr->get_remote_proc(),
           ptr->get_given_size(), ptr->get_sent_size(),
           ptr->get_tag_ev(), ptr->get_tag_av(),
           ptr->get_offset(), ptr->get_rarg(0),
           ptr->get_rarg(1));
   fflush(Sdf::trace);
   ptr->set_handler(rts_handler, 0);
   return source_data_ptr;
}

class Root_thread: public Thread{
   public:
        Root_thread()
                : Thread((Tmf0_ptr)&Root_thread::body){}

        void body(){
           fprintf(Sdf::trace, "from node%d: this is my rank\n", Sdf::PROC_ID);
           fflush(Sdf::trace);
           fflush(Sdf::trace);
           int source_data;
           int dest_data;
           source_data_ptr = &source_data;

           source_data  = Sdf::PROC_ID;
           dest_data    = 100+Sdf::PROC_ID; //to check value change in trace

           fprintf(Sdf::trace, "node%d: s=%d, d=%d\n",
                    Sdf::PROC_ID, source_data, dest_data);
           fflush(Sdf::trace);

           Global<int> global_s(gid1, rloc_fct);
            //the defined Global data have Sdf::INDIR access type
             //(address to the data is not in the Global, it is computed
             //on the fly by using rwloc_fct).
           Sdf::barrier(cid1);

           Star<int> global_s_ptr((Sdf::PROC_ID+Sdf::PROC_NB-1)%Sdf::PROC_NB, global_s, 
                                  (unsigned long)0, Sdf::NORA, Sdf::NOAP, Sdf::NOCP); 
           Star<int> global_d_ptr(gid2, &dest_data);
            //Local pointer &dest_data is turned into a Global pointer with Sdf::DIR
            //access type to data.
            //Pointer to control record is implicitely set to Sdf::NOCP so that 
            //writins is blocking.

           int rarg_r[2] = {50,100};    //just to check values in trace
           global_s_ptr.set_rarg(rarg_r);

           *global_d_ptr = *global_s_ptr;
            //global writing is blocking. Assignment does not return until
            //writing is over (reading completion is handled automatically
            //by library).

           Sdf::barrier(cid2);
               //global syncro before printing

           fprintf(Sdf::trace, "node%d: s=%d, d=%d\n",
                        Sdf::PROC_ID, source_data, dest_data);
           fflush(Sdf::trace);
        }
};

MAIN(Root_thread, init_gid, Sdf::empty, Sdf::empty)

